﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="BBD.cs" company="">
//   
// </copyright>
// <summary>
//   The bbd.
// </summary>
// --------------------------------------------------------------------------------------------------------------------


using System;
using System.Collections.Generic;
using System.Linq;
using Systemathics.FrameWork;

namespace Systemathics.Indicators
{

    [Serializable]
    public sealed class BBD : Indicator
    {
        private readonly Decimal a;
        private readonly Decimal b;
        private readonly Decimal c;
        private readonly Queue<Decimal> queue;
        private Decimal mu;
        private Decimal sigma_squarre;

        public int    Length        { get; private set; }
        public double Sigma         { get; private set; }
        public Decimal LastMean     { get { return mu; } }
        public double LastSigma { get { return Math.Sqrt((double) sigma_squarre); } }

        public BBD(Instrument instr, Data dt, BarType bt, int barValue,int length, double sigma): base(instr ,dt ,  bt, barValue)
        {
            Length = length;
            Sigma = sigma;

            a = (Decimal)(Length - 1) / Length;
            b = 1 / (Decimal)Length;
            c = 1 / (Decimal)(Length - 1);
            mu = 0;
            sigma_squarre = 0;
            queue = new Queue<Decimal>();
        }

        protected override void Calculate(object price)
        {
            if (price is Bar)
            {
                var bar = price as Bar;
                Calculate(bar.BeginTime, bar.Low);
            }
            else if (price is Quote)
            {
                var quote = price as Quote;
                Calculate(quote.Time, quote.Mid);
            }
            else
            {
                var trade = price as Trade;
                Calculate(trade.Time, trade.Price);
            }
        }

        private void Calculate(DateTime time, Decimal value)
        {
            if (queue.Count < Length)
            {
                queue.Enqueue(value);
                mu = queue.Average();
            }
            else
            {
                mu = a*mu + b*value;
                sigma_squarre = a * sigma_squarre + c * (value - mu) * (value - mu);
                Add(time, mu - (decimal) (Sigma*Math.Sqrt((double) sigma_squarre)));
                IndicatorCalculated(this);
            }
        }
    }
}